package org.eden.rpc.core.server;

import org.eden.rpc.common.entity.RpcRequest;
import org.eden.rpc.common.enumerate.ErrorCode;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;

public class DefaultServiceRegister implements ServiceRegister{

    private final Logger logger = LoggerFactory.getLogger(this.getClass());

    private final Map<String, Object> services = new HashMap<>();

    private final Set<String> registeredServices = new HashSet<>();

    @Override
    public synchronized void register(Object service) {
        String canonicalName = service.getClass().getCanonicalName();
        if (registeredServices.contains(canonicalName)) {
            logger.error(ErrorCode.SERVICE_HAS_BEEN_REGISTERED.getMsg());
            throw new RuntimeException(ErrorCode.SERVICE_HAS_BEEN_REGISTERED.getMsg());
        }
        registeredServices.add(canonicalName);
        Class<?>[] interfaces = service.getClass().getInterfaces();
        if (interfaces.length == 0) {
            logger.error(ErrorCode.SERVICE_NOT_IMPLEMENT_ANY_INTERFACE.getMsg());
            throw new RuntimeException(ErrorCode.SERVICE_NOT_IMPLEMENT_ANY_INTERFACE.getMsg());
        }
        for (Class<?> c : interfaces) {
            services.put(c.getCanonicalName(), service);
        }
        logger.info("成功注册服务: " + canonicalName);
    }

    @Override
    public Object getService(String serviceName) {
        Object service = services.get(serviceName);
        if (service == null) {
            logger.error(ErrorCode.SERVICE_NOT_FOUND.getMsg());
            throw new RuntimeException(ErrorCode.SERVICE_NOT_FOUND.getMsg());
        }
        return service;
    }

    public Object invoke(Object service, RpcRequest request) {
        try {
            Method method = service.getClass().getMethod(request.getMethodName(), request.getParamType());
            return method.invoke(service, request.getParameters());
        } catch (NoSuchMethodException | InvocationTargetException | IllegalAccessException e) {
            logger.error(e.getMessage());
        }
        return null;
    }
}
